 /*
 * GSS - Work with Google AJAX Search API using jQuery
 * Version 0.1.3
 * @requires jQuery v1.4.2 or greater
 *
 * Examples and docs at:
 * http://gss.codeplex.com
 * Licensed under the MIT license:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * @description GSS - Work with Google AJAX Search API using jQuery
 * @type jQuery
 * @name gss
 * @category Plugins/gss
 * @author Andrew S Porter / andrewporter2010@gmail.com
 */

/******************************  Global Variables  *******************************/
var _debug = false;
var haveInitializedGlobals = false;
var theSearchControl;
var theSearchForm;
var theSearcherOptions; //once this is used in a .addSearcher call, its properties are set to undefined
var theDrawOptions;

var theWebSearch;
var theLocalSearch;
var theVideoSearch;
var theBlogSearch;
var theNewsSearch;
var theBookSearch;
var theImageSearch;
var thePatentSearch;

/******************************  Constructors  *******************************/

jQuery.fn.GoogleWebSearch = function(o) {
	$.initializeGlobals();

	//IMPORTANT: Some Searcher methods need to be called AFTER the Searcher is added
	if (o) {
		$.applyGlobalOptions(o);
		$.applySearcherOptions(o);
		$.applyDrawOptions(o);

		if(o.resultSetSize) {	
			switch(o.resultSetSize) {			
				case "small" :
					theWebSearch.setResultSetSize(google.search.Search.SMALL_RESULTSET);
					break;
				case "large" :
					theWebSearch.setResultSetSize(google.search.Search.LARGE_RESULTSET);
					break;
				default :
					$.warn("resultSetSize", o.resultSetSize);
			}
		}
		if(o.searchCompleteCallback) theWebSearch.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
		if(o.userDefinedLabel) theWebSearch.setUserDefinedLabel(o.userDefinedLabel);
		if(o.userDefinedClassSuffix) theWebSearch.setUserDefinedClassSuffix(o.userDefinedClassSuffix);
		if(o.noHtmlGeneration) theWebSearch.setNoHtmlGeneration();
		if(o.queryAddition) theWebSearch.setQueryAddition(o.queryAddition);
		if(o.resultHtml) theWebSearch.createResultHtml(o.resultHtml);
		if(o.goToPage) theWebSearch.gotoPage(o.goToPage);
		
		//CUSTOM OPTIONS BELOW
		if(o.siteRestriction) theWebSearch.setSiteRestriction(o.siteRestriction);
	}
	//end options	
	
	return this.each(function() {
/*******/
		if(o) {
			if(o.customControl == true) {
				if (o.execute) {
					theWebSearch.execute(o.execute);
				}				
			}
			else {
				if(o.searchCompleteCallback) theSearchControl.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
				theSearchControl.addSearcher(theWebSearch, theSearcherOptions);			
				// Tell the searcher to draw itself and tell it where to attach
				//$.log(theDrawOptions.inputElement);
				theSearchControl.draw(this, theDrawOptions);			
			}
		}
		else {
			if(o) {
				if(o.searchCompleteCallback) theSearchControl.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
			}
			theSearchControl.addSearcher(theWebSearch, theSearcherOptions);			
			// Tell the searcher to draw itself and tell it where to attach
			//$.log(theDrawOptions.inputElement);
			theSearchControl.draw(this, theDrawOptions);
		}
/*******/
		//if user supplied [execute, noResultsString] handle
		if (o) {
			if (o.noResultsString) {
				theSearchControl.setNoResultsString(o.noResultsString);
			}
			if (o.execute && !o.customControl) {							//changes here
				theSearchControl.execute(o.execute);
			}
			if(o.linkTarget) {
				switch (o.linkTarget) {
					case "_blank" : 
						theWebSearch.setLinkTarget(google.search.Search.LINK_TARGET_BLANK);
						break;
					case "_self" :
						theWebSearch.setLinkTarget(google.search.Search.LINK_TARGET_SELF);
						break;
					case "_top" :
						theWebSearch.setLinkTarget(google.search.Search.LINK_TARGET_TOP);
						break;
					case "_parent" :
						theWebSearch.setLinkTarget(google.search.Search.LINK_TARGET_PARENT);
						break;
					default:
						$.warn("linkTarget", o.linkTarget);
						theWebSearch.setLinkTarget(o.linkTarget);
				}
			}			
		}
	});	
};

jQuery.fn.GoogleLocalSearch = function(o) {
	$.initializeGlobals();
	
		//IMPORTANT: Some Searcher methods need to be called AFTER the Searcher is added
	if (o) {
		$.applyGlobalOptions(o);
		$.applySearcherOptions(o);
		$.applyDrawOptions(o);

		if(o.resultSetSize) {	
			switch(o.resultSetSize) {			
				case "small" :
					theLocalSearch.setResultSetSize(google.search.Search.SMALL_RESULTSET);
					break;
				case "large" :
					theLocalSearch.setResultSetSize(google.search.Search.LARGE_RESULTSET);
					break;
				default :
					$.warn("resultSetSize", o.resultSetSize);
			}
		}
		if(o.searchCompleteCallback) theLocalSearch.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
		if(o.userDefinedLabel) theLocalSearch.setUserDefinedLabel(o.userDefinedLabel);
		if(o.userDefinedClassSuffix) theLocalSearch.setUserDefinedClassSuffix(o.userDefinedClassSuffix);
		if(o.noHtmlGeneration) theLocalSearch.setNoHtmlGeneration();
		if(o.queryAddition) theLocalSearch.setQueryAddition(o.queryAddition);
		if(o.resultHtml) theLocalSearch.createResultHtml(o.resultHtml);
		if(o.goToPage) theLocalSearch.gotoPage(o.goToPage);
		
		//CUSTOM OPTIONS BELOW
		if(o.centerPoint) theLocalSearch.setCenterPoint(o.centerPoint);
	}
	//end options		
		
	return this.each(function() {	
/*******/
		if(o) {
			if(o.customControl == true) {
				if (o.execute) {
					theLocalSearch.execute(o.execute);
				}				
			}
			else {
				if(o.searchCompleteCallback) theSearchControl.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
				theSearchControl.addSearcher(theLocalSearch, theSearcherOptions);			
				// Tell the searcher to draw itself and tell it where to attach
				//$.log(theDrawOptions.inputElement);
				theSearchControl.draw(this, theDrawOptions);			
			}
		}
		else {
			if(o) {
				if(o.searchCompleteCallback) theSearchControl.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
			}
			theSearchControl.addSearcher(theLocalSearch, theSearcherOptions);			
			// Tell the searcher to draw itself and tell it where to attach
			//$.log(theDrawOptions.inputElement);
			theSearchControl.draw(this, theDrawOptions);
		}
/*******/
		
		//if user supplied [execute, noResultsString] handle
		if (o) {
			if (o.noResultsString) {
				theSearchControl.setNoResultsString(o.noResultsString);
			}
			if (o.execute && !o.customControl) {
				theSearchControl.execute(o.execute);
			}
			if(o.linkTarget) {
				switch (o.linkTarget) {
					case "_blank" : 
						theLocalSearch.setLinkTarget(google.search.Search.LINK_TARGET_BLANK);
						break;
					case "_self" :
						theLocalSearch.setLinkTarget(google.search.Search.LINK_TARGET_SELF);
						break;
					case "_top" :
						theLocalSearch.setLinkTarget(google.search.Search.LINK_TARGET_TOP);
						break;
					case "_parent" :
						theLocalSearch.setLinkTarget(google.search.Search.LINK_TARGET_PARENT);
						break;
					default:
						$.warn("linkTarget", o.linkTarget);
						theLocalSearch.setLinkTarget(o.linkTarget);
				}
			}				
		}
	});	
};

jQuery.fn.GoogleVideoSearch = function(o) {
	$.initializeGlobals();
	
	if (o) {
		$.applyGlobalOptions(o);
		$.applySearcherOptions(o);
		$.applyDrawOptions(o);
		
		if(o.resultSetSize) {	
			switch(o.resultSetSize) {			
				case "small" :
					theVideoSearch.setResultSetSize(google.search.Search.SMALL_RESULTSET);
					break;
				case "large" :
					theVideoSearch.setResultSetSize(google.search.Search.LARGE_RESULTSET);
					break;
				default :
					$.warn("resultSetSize", o.resultSetSize);
			}
		}
		if(o.searchCompleteCallback) theVideoSearch.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
		if(o.userDefinedLabel) theVideoSearch.setUserDefinedLabel(o.userDefinedLabel);
		if(o.userDefinedClassSuffix) theVideoSearch.setUserDefinedClassSuffix(o.userDefinedClassSuffix);
		if(o.noHtmlGeneration) theVideoSearch.setNoHtmlGeneration();
		if(o.queryAddition) theVideoSearch.setQueryAddition(o.queryAddition);
		if(o.resultHtml) theVideoSearch.createResultHtml(o.resultHtml);
		if(o.goToPage) theVideoSearch.gotoPage(o.goToPage);
		
		//CUSTOM OPTIONS BELOW
		if(o.resultOrder) {
			switch(o.resultOrder) {			
				case "relevance" :
					theVideoSearch.setResultOrder(google.search.Search.ORDER_BY_RELEVANCE);
					break;
				case "date" :
					theVideoSearch.setResultOrder(google.search.Search.ORDER_BY_DATE);
					break;
				default :
					$.warn("resultOrder", o.resultOrder);
			}
		}
	}
	//end options
		
	return this.each(function() {
/*******/
		if(o) {
			if(o.customControl == true) {
				if (o.execute) {
					theVideoSearch.execute(o.execute);
				}				
			}
			else {
				if(o.searchCompleteCallback) theSearchControl.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
				theSearchControl.addSearcher(theVideoSearch, theSearcherOptions);			
				// Tell the searcher to draw itself and tell it where to attach
				//$.log(theDrawOptions.inputElement);
				theSearchControl.draw(this, theDrawOptions);			
			}
		}
		else {
			if(o) {
				if(o.searchCompleteCallback) theSearchControl.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
			}
			theSearchControl.addSearcher(theVideoSearch, theSearcherOptions);			
			// Tell the searcher to draw itself and tell it where to attach
			//$.log(theDrawOptions.inputElement);
			theSearchControl.draw(this, theDrawOptions);
		}
/*******/
		//if user supplied [execute, noResultsString] handle
		if (o) {
			if (o.noResultsString) {
				theSearchControl.setNoResultsString(o.noResultsString);
			}
			if (o.execute && !o.customControl) {
				theSearchControl.execute(o.execute);
			}
			if(o.linkTarget) {
				switch (o.linkTarget) {
					case "_blank" : 
						theVideoSearch.setLinkTarget(google.search.Search.LINK_TARGET_BLANK);
						break;
					case "_self" :
						theVideoSearch.setLinkTarget(google.search.Search.LINK_TARGET_SELF);
						break;
					case "_top" :
						theVideoSearch.setLinkTarget(google.search.Search.LINK_TARGET_TOP);
						break;
					case "_parent" :
						theVideoSearch.setLinkTarget(google.search.Search.LINK_TARGET_PARENT);
						break;
					default:
						$.warn("linkTarget", o.linkTarget);
						theVideoSearch.setLinkTarget(o.linkTarget);
				}
			}					
		}
	});	
};

jQuery.fn.GoogleBlogSearch = function(o) {
	$.initializeGlobals();
	
	if (o) {
		$.applyGlobalOptions(o);
		$.applySearcherOptions(o);
		$.applyDrawOptions(o);
		
		if(o.resultSetSize) {	
			switch(o.resultSetSize) {			
				case "small" :
					theBlogSearch.setResultSetSize(google.search.Search.SMALL_RESULTSET);
					break;
				case "large" :
					theBlogSearch.setResultSetSize(google.search.Search.LARGE_RESULTSET);
					break;
				default :
					$.warn("resultSetSize", o.resultSetSize);
			}
		}
		if(o.searchCompleteCallback) theBlogSearch.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
		if(o.userDefinedLabel) theBlogSearch.setUserDefinedLabel(o.userDefinedLabel);
		if(o.userDefinedClassSuffix) theBlogSearch.setUserDefinedClassSuffix(o.userDefinedClassSuffix);
		if(o.noHtmlGeneration) theBlogSearch.setNoHtmlGeneration();
		if(o.queryAddition) theBlogSearch.setQueryAddition(o.queryAddition);
		if(o.resultHtml) theBlogSearch.createResultHtml(o.resultHtml);
		if(o.goToPage) theBlogSearch.gotoPage(o.goToPage);
		
		//CUSTOM OPTIONS BELOW
		if(o.siteRestriction) theBlogSearch.setSiteRestriction(o.siteRestriction);
		if(o.resultOrder) {
			switch(o.resultOrder) {			
				case "relevance" :
					theBlogSearch.setResultOrder(google.search.Search.ORDER_BY_RELEVANCE);
					break;
				case "date" :
					theBlogSearch.setResultOrder(google.search.Search.ORDER_BY_DATE);
					break;
				default :
					$.warn("resultOrder", o.resultOrder);
			}
		}
	}
	//end options

	return this.each(function() {
/*******/
		if(o) {
			if(o.customControl == true) {
				if (o.execute) {
					theBlogSearch.execute(o.execute);
				}				
			}
			else {
				if(o.searchCompleteCallback) theSearchControl.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
				theSearchControl.addSearcher(theBlogSearch, theSearcherOptions);			
				// Tell the searcher to draw itself and tell it where to attach
				//$.log(theDrawOptions.inputElement);
				theSearchControl.draw(this, theDrawOptions);			
			}
		}
		else {
			if(o) {
				if(o.searchCompleteCallback) theSearchControl.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
			}
			theSearchControl.addSearcher(theBlogSearch, theSearcherOptions);			
			// Tell the searcher to draw itself and tell it where to attach
			//$.log(theDrawOptions.inputElement);
			theSearchControl.draw(this, theDrawOptions);
		}
/*******/
		//if user supplied [execute, noResultsString] handle
		if (o) {
			if (o.noResultsString) {
				theSearchControl.setNoResultsString(o.noResultsString);
			}
			if (o.execute && !o.customControl) {
				theSearchControl.execute(o.execute);
			}
			if(o.linkTarget) {
				switch (o.linkTarget) {
					case "_blank" : 
						theBlogSearch.setLinkTarget(google.search.Search.LINK_TARGET_BLANK);
						break;
					case "_self" :
						theBlogSearch.setLinkTarget(google.search.Search.LINK_TARGET_SELF);
						break;
					case "_top" :
						theBlogSearch.setLinkTarget(google.search.Search.LINK_TARGET_TOP);
						break;
					case "_parent" :
						theBlogSearch.setLinkTarget(google.search.Search.LINK_TARGET_PARENT);
						break;
					default:
						$.warn("linkTarget", o.linkTarget);
						theBlogSearch.setLinkTarget(o.linkTarget);
				}
			}				
		}
	});	
};

jQuery.fn.GoogleNewsSearch = function(o) {
	$.initializeGlobals();
	
	if (o) {
		$.applyGlobalOptions(o);
		$.applySearcherOptions(o);
		$.applyDrawOptions(o);
		
		if(o.resultSetSize) {	
			switch(o.resultSetSize) {			
				case "small" :
					theNewsSearch.setResultSetSize(google.search.Search.SMALL_RESULTSET);
					break;
				case "large" :
					theNewsSearch.setResultSetSize(google.search.Search.LARGE_RESULTSET);
					break;
				default :
					$.warn("resultSetSize", o.resultSetSize);
			}
		}
		if(o.searchCompleteCallback) theNewsSearch.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
		if(o.userDefinedLabel) theNewsSearch.setUserDefinedLabel(o.userDefinedLabel);
		if(o.userDefinedClassSuffix) theNewsSearch.setUserDefinedClassSuffix(o.userDefinedClassSuffix);
		if(o.noHtmlGeneration) theNewsSearch.setNoHtmlGeneration();
		if(o.queryAddition) theNewsSearch.setQueryAddition(o.queryAddition);
		if(o.resultHtml) theNewsSearch.createResultHtml(o.resultHtml);
		if(o.goToPage) theNewsSearch.gotoPage(o.goToPage);
		
		//CUSTOM OPTIONS BELOW
		if(o.siteRestriction) theNewsSearch.setSiteRestriction(o.siteRestriction);
		if(o.resultOrder) {
			switch(o.resultOrder) {			
				case "relevance" :
					theNewsSearch.setResultOrder(google.search.Search.ORDER_BY_RELEVANCE);
					break;
				case "date" :
					theNewsSearch.setResultOrder(google.search.Search.ORDER_BY_DATE);
					break;
				default :
					$.warn("resultOrder", o.resultOrder);
			}
		}
	}
	//end options
		
	return this.each(function() {
/*******/
		if(o) {
			if(o.customControl == true) {
				if (o.execute) {
					theNewsSearch.execute(o.execute);
				}				
			}
			else {
				if(o.searchCompleteCallback) theSearchControl.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
				theSearchControl.addSearcher(theNewsSearch, theSearcherOptions);			
				// Tell the searcher to draw itself and tell it where to attach
				//$.log(theDrawOptions.inputElement);
				theSearchControl.draw(this, theDrawOptions);			
			}
		}
		else {
			if(o) {
				if(o.searchCompleteCallback) theSearchControl.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
			}
			theSearchControl.addSearcher(theNewsSearch, theSearcherOptions);			
			// Tell the searcher to draw itself and tell it where to attach
			//$.log(theDrawOptions.inputElement);
			theSearchControl.draw(this, theDrawOptions);
		}
/*******/
		//if user supplied [execute, noResultsString] handle
		if (o) {
			if (o.noResultsString) {
				theSearchControl.setNoResultsString(o.noResultsString);
			}
			if (o.execute && !o.customControl) {
				theSearchControl.execute(o.execute);
			}
			if(o.linkTarget) {
				switch (o.linkTarget) {
					case "_blank" : 
						theNewsSearch.setLinkTarget(google.search.Search.LINK_TARGET_BLANK);
						break;
					case "_self" :
						theNewsSearch.setLinkTarget(google.search.Search.LINK_TARGET_SELF);
						break;
					case "_top" :
						theNewsSearch.setLinkTarget(google.search.Search.LINK_TARGET_TOP);
						break;
					case "_parent" :
						theNewsSearch.setLinkTarget(google.search.Search.LINK_TARGET_PARENT);
						break;
					default:
						$.warn("linkTarget", o.linkTarget);
						theNewsSearch.setLinkTarget(o.linkTarget);
				}
			}				
		}
	});	
};

jQuery.fn.GoogleImageSearch = function(o) {
	$.initializeGlobals();
	
	if (o) {
		$.applyGlobalOptions(o);
		$.applySearcherOptions(o);
		$.applyDrawOptions(o);

		if(o.resultSetSize) {	
			switch(o.resultSetSize) {			
				case "small" :
					theImageSearch.setResultSetSize(google.search.Search.SMALL_RESULTSET);
					break;
				case "large" :
					theImageSearch.setResultSetSize(google.search.Search.LARGE_RESULTSET);
					break;
				default :
					$.warn("resultSetSize", o.resultSetSize);
			}
		}
		if(o.searchCompleteCallback) theImageSearch.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
		if(o.userDefinedLabel) theImageSearch.setUserDefinedLabel(o.userDefinedLabel);
		if(o.userDefinedClassSuffix) theImageSearch.setUserDefinedClassSuffix(o.userDefinedClassSuffix);
		if(o.noHtmlGeneration) theImageSearch.setNoHtmlGeneration();
		if(o.queryAddition) theImageSearch.setQueryAddition(o.queryAddition);
		if(o.resultHtml) theImageSearch.createResultHtml(o.resultHtml);
		if(o.goToPage) theImageSearch.gotoPage(o.goToPage);
		
		//CUSTOM OPTIONS BELOW
		if(o.siteRestriction) theImageSearch.setSiteRestriction(o.siteRestriction);
	}
	//end options
		
	return this.each(function() {
/*******/
		if(o) {
			if(o.customControl == true) {
				if (o.execute) {
					theImageSearch.execute(o.execute);
				}				
			}
			else {
				if(o.searchCompleteCallback) theSearchControl.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
				theSearchControl.addSearcher(theImageSearch, theSearcherOptions);			
				// Tell the searcher to draw itself and tell it where to attach
				//$.log(theDrawOptions.inputElement);
				theSearchControl.draw(this, theDrawOptions);			
			}
		}
		else {
			if(o) {
				if(o.searchCompleteCallback) theSearchControl.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
			}
			theSearchControl.addSearcher(theImageSearch, theSearcherOptions);			
			// Tell the searcher to draw itself and tell it where to attach
			//$.log(theDrawOptions.inputElement);
			theSearchControl.draw(this, theDrawOptions);
		}
/*******/
		//if user supplied [execute, noResultsString] handle
		if (o) {
			if (o.noResultsString) {
				theSearchControl.setNoResultsString(o.noResultsString);
			}
			if (o.execute && !o.customControl) {
				theSearchControl.execute(o.execute);
			}
			if(o.linkTarget) {
				switch (o.linkTarget) {
					case "_blank" : 
						theImageSearch.setLinkTarget(google.search.Search.LINK_TARGET_BLANK);
						break;
					case "_self" :
						theImageSearch.setLinkTarget(google.search.Search.LINK_TARGET_SELF);
						break;
					case "_top" :
						theImageSearch.setLinkTarget(google.search.Search.LINK_TARGET_TOP);
						break;
					case "_parent" :
						theImageSearch.setLinkTarget(google.search.Search.LINK_TARGET_PARENT);
						break;
					default:
						$.warn("linkTarget", o.linkTarget);
						theImageSearch.setLinkTarget(o.linkTarget);
				}
			}				
		}
	});	
};

jQuery.fn.GoogleBookSearch = function(o) {
	$.initializeGlobals();
	
	if (o) {
		$.applyGlobalOptions(o);
		$.applySearcherOptions(o);
		$.applyDrawOptions(o);
		
		if(o.resultSetSize) {	
			switch(o.resultSetSize) {			
				case "small" :
					theBookSearch.setResultSetSize(google.search.Search.SMALL_RESULTSET);
					break;
				case "large" :
					theBookSearch.setResultSetSize(google.search.Search.LARGE_RESULTSET);
					break;
				default :
					$.warn("resultSetSize", o.resultSetSize);
			}
		}
		if(o.searchCompleteCallback) theBookSearch.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
		if(o.userDefinedLabel) theBookSearch.setUserDefinedLabel(o.userDefinedLabel);
		if(o.userDefinedClassSuffix) theBookSearch.setUserDefinedClassSuffix(o.userDefinedClassSuffix);
		if(o.noHtmlGeneration) theBookSearch.setNoHtmlGeneration();
		if(o.queryAddition) theBookSearch.setQueryAddition(o.queryAddition);
		if(o.resultHtml) theBookSearch.createResultHtml(o.resultHtml);
		if(o.goToPage) theBookSearch.gotoPage(o.goToPage);
	}
		
	return this.each(function() {
/*******/
		if(o) {
			if(o.customControl == true) {
				if (o.execute) {
					theBookSearch.execute(o.execute);
				}				
			}
			else {
				if(o.searchCompleteCallback) theSearchControl.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
				theSearchControl.addSearcher(theBookSearch, theSearcherOptions);			
				// Tell the searcher to draw itself and tell it where to attach
				//$.log(theDrawOptions.inputElement);
				theSearchControl.draw(this, theDrawOptions);			
			}
		}
		else {
			if(o) {
				if(o.searchCompleteCallback) theSearchControl.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
			}
			theSearchControl.addSearcher(theBookSearch, theSearcherOptions);			
			// Tell the searcher to draw itself and tell it where to attach
			//$.log(theDrawOptions.inputElement);
			theSearchControl.draw(this, theDrawOptions);
		}
/*******/
		//if user supplied [execute, noResultsString, linkTarget] handle
		if (o) {
			if (o.noResultsString) {
				theSearchControl.setNoResultsString(o.noResultsString);
			}
			if (o.execute && !o.customControl) {
				theSearchControl.execute(o.execute);
			}
			if(o.linkTarget) {
				switch (o.linkTarget) {
					case "_blank" : 
						theBookSearch.setLinkTarget(google.search.Search.LINK_TARGET_BLANK);
						break;
					case "_self" :
						theBookSearch.setLinkTarget(google.search.Search.LINK_TARGET_SELF);
						break;
					case "_top" :
						theBookSearch.setLinkTarget(google.search.Search.LINK_TARGET_TOP);
						break;
					case "_parent" :
						theBookSearch.setLinkTarget(google.search.Search.LINK_TARGET_PARENT);
						break;
					default:
						$.warn("linkTarget", o.linkTarget);
						theBookSearch.setLinkTarget(o.linkTarget);
				}
			}				
		}
	});	
};

jQuery.fn.GooglePatentSearch = function(o) {
	$.initializeGlobals();
	
	if (o) {
		$.applyGlobalOptions(o);
		$.applySearcherOptions(o);
		$.applyDrawOptions(o);
		
		if(o.resultSetSize) {	
			switch(o.resultSetSize) {			
				case "small" :
					thePatentSearch.setResultSetSize(google.search.Search.SMALL_RESULTSET);
					break;
				case "large" :
					thePatentSearch.setResultSetSize(google.search.Search.LARGE_RESULTSET);
					break;
				default :
					$.warn("resultSetSize", o.resultSetSize);
			}
		}
		if(o.searchCompleteCallback) thePatentSearch.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
		if(o.userDefinedLabel) thePatentSearch.setUserDefinedLabel(o.userDefinedLabel);
		if(o.userDefinedClassSuffix) thePatentSearch.setUserDefinedClassSuffix(o.userDefinedClassSuffix);
		if(o.noHtmlGeneration) thePatentSearch.setNoHtmlGeneration();
		if(o.queryAddition) thePatentSearch.setQueryAddition(o.queryAddition);
		if(o.resultHtml) thePatentSearch.createResultHtml(o.resultHtml);
		if(o.goToPage) thePatentSearch.gotoPage(o.goToPage);
		
		//CUSTOM OPTIONS BELOW
		if(o.resultOrder) {
			switch(o.resultOrder) {			
				case "relevance" :
					thePatentSearch.setResultOrder(google.search.Search.ORDER_BY_RELEVANCE);
					break;
				case "date" :
					thePatentSearch.setResultOrder(google.search.Search.ORDER_BY_DATE);
					break;
				default :
					$.warn("resultOrder", o.resultOrder);
			}
		}
	}
	//end options
		
	return this.each(function() {
/*******/
		if(o) {
			if(o.customControl == true) {
				if (o.execute) {
					thePatentSearch.execute(o.execute);
				}				
			}
			else {
				if(o.searchCompleteCallback) theSearchControl.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
				theSearchControl.addSearcher(thePatentSearch, theSearcherOptions);			
				// Tell the searcher to draw itself and tell it where to attach
				//$.log(theDrawOptions.inputElement);
				theSearchControl.draw(this, theDrawOptions);			
			}
		}
		else {
			if(o) {
				if(o.searchCompleteCallback) theSearchControl.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
			}
			theSearchControl.addSearcher(thePatentSearch, theSearcherOptions);			
			// Tell the searcher to draw itself and tell it where to attach
			//$.log(theDrawOptions.inputElement);
			theSearchControl.draw(this, theDrawOptions);
		}
/*******/
		//if user supplied [execute, noResultsString] handle
		if (o) {
			if (o.noResultsString)
				theSearchControl.setNoResultsString(o.noResultsString);
			if (o.execute && !o.customControl) {
				theSearchControl.execute(o.execute);
			}
			if(o.linkTarget) {
				switch (o.linkTarget) {
					case "_blank" : 
						thePatentSearch.setLinkTarget(google.search.Search.LINK_TARGET_BLANK);
						break;
					case "_self" :
						thePatentSearch.setLinkTarget(google.search.Search.LINK_TARGET_SELF);
						break;
					case "_top" :
						thePatentSearch.setLinkTarget(google.search.Search.LINK_TARGET_TOP);
						break;
					case "_parent" :
						thePatentSearch.setLinkTarget(google.search.Search.LINK_TARGET_PARENT);
						break;
					default:
						$.warn("linkTarget", o.linkTarget);
						thePatentSearch.setLinkTarget(o.linkTarget);
				}
			}				
		}
	});	
};

/******************************  Modifiers  *******************************/

jQuery.fn.setGlobalTimeoutInterval = function (timeoutInterval) {
	switch (timeoutInterval) {
		case "short" :
			theSearchControl.setTimeoutInterval(google.search.SearchControl.TIMEOUT_SHORT);
			break;
		case "medium" :
			theSearchControl.setTimeoutInterval(google.search.SearchControl.TIMEOUT_MEDIUM);
			break;
		case "long" :
			theSearchControl.setTimeoutInterval(google.search.SearchControl.TIMEOUT_LONG);
			break;
		default:
			$.warn("timeoutInterval", timeoutInterval);
	}
}

jQuery.fn.execute = function (opt_query) {
	theSearchControl.execute(opt_query);
}

jQuery.fn.setGlobalOnKeepCallback = function(object, method, opt_keepLabel) {
	if(opt_keepLabel)
		theSearchControl.setOnKeepCallback(object, method, opt_keepLabel)
	else
		theSearchControl.setOnKeepCallback(object, method);
}

jQuery.fn.setGlobalResultSetSize = function(switchTo) {
	switch(switchTo) {			
		case "small" :
			theSearchControl.setResultSetSize(google.search.Search.SMALL_RESULTSET);
			break;
		case "large" :
			theSearchControl.setResultSetSize(google.search.Search.LARGE_RESULTSET);
			break;
		default :
			$.warn("resultSetSize", resultSetSize);
	}
}

jQuery.fn.cancelSearch = function() {
	theSearchControl.cancelSearch();
}

jQuery.fn.clearAllResults = function() {
	theSearchControl.clearAllResults();
}

jQuery.fn.setGlobalLinkTarget = function(linkTarget) {
	switch (linkTarget) {
		case "_blank" : 
			theSearchControl.setLinkTarget(google.search.Search.LINK_TARGET_BLANK);
			break;
		case "_self" :
			theSearchControl.setLinkTarget(google.search.Search.LINK_TARGET_SELF);
			break;
		case "_top" :
			theSearchControl.setLinkTarget(google.search.Search.LINK_TARGET_TOP);
			break;
		case "_parent" :
			theSearchControl.setLinkTarget(google.search.Search.LINK_TARGET_PARENT);
			break;
		default:
			$.warn("linkTarget", linkTarget);
			theSearchControl.setLinkTarget(linkTarget);
	}
}

jQuery.fn.setGlobalSearchCompleteCallback = function(object, method) {
	theSearchControl.setSearchCompleteCallback(object, method);
}

jQuery.fn.setGlobalSearchStartingCallback = function(object, method) {
	theSearchControl.setSearchStartingCallback(object, method);
}

jQuery.fn.setGlobalNoResultsString = function(str) {
	theSearchControl.setNoResultsString(str);
}

/******************************  SearchForm *******************************/

jQuery.fn.SearchForm = function (enableClear, element) {
	theSearchForm = new google.search.SearchForm(enableClear, element);	
}

jQuery.fn.setOnSubmitCallback = function(object, method) {
	theSearchForm.setOnSubmitCallback(object, method);
}

jQuery.fn.setOnClearCallback = function(object, method) {
	theSearchForm.setOnClearCallback(object, method);
}

jQuery.fn.fExecute = function(opt_string) {
	theSearchForm.execute(opt_string);
}

/******************************  Utility  *******************************/

jQuery.applyDrawOptions = function (o) {
	if(o.inputElement) {
		theDrawOptions.setInput(o.inputElement);
	}
	if(o.drawMode) {
		switch(o.drawMode) {
			case "linear" :
				theDrawOptions.setDrawMode(google.search.SearchControl.DRAW_MODE_LINEAR);
				break;
			case "tabbed" :
				theDrawOptions.setDrawMode(google.search.SearchControl.DRAW_MODE_TABBED);
				break;
			default : 
				$.warn("drawMode", o.drawMode);
		}
	}
	if(o.searchFormRoot) {
		//$.log(o.searchFormRoot);
		theDrawOptions.setSearchFormRoot(o.searchFormRoot);
	}
}

jQuery.applySearcherOptions = function (o) {
	if(o.resultsRoot) {
		theSearcherOptions.setRoot(o.resultsRoot);
	}
	if(o.expandMode) {	
		switch (o.expandMode) {
			case "closed" :
				theSearcherOptions.setExpandMode(google.search.SearchControl.EXPAND_MODE_CLOSED);
				break;
			case "open" :
				theSearcherOptions.setExpandMode(google.search.SearchControl.EXPAND_MODE_OPEN);
				break;
			case "partial" :
				theSearcherOptions.setExpandMode(google.search.SearchControl.EXPAND_MODE_PARTIAL);
				break;
			default :
				$.warn("expandMode", o.expandMode);
		}
	}
	if(o.videoResultsTbHeight) {
		theSearcherOptions.setVideoResultsTbHeight(o.videoResultsTbHeight);
	}
	if(o.imageResultsTbHeight) {
		theSearcherOptions.setImageResultsTbHeight(o.imageResultsTbHeight);
	}
}

//apply options to theSearchControl before draw/execute
jQuery.applyGlobalOptions = function (o) {
	//for debugging, print out entire options
	if(_debug) {
		$.log("options = {");
		$.each(o, function (index, value) {
			$.log("  " + index + ' : ' + value);
		});
		$.log("}");
	}
	
	if(o.timeoutInterval) $.fn.setGlobalTimeoutInterval(o.timeoutInterval);
	if(o.onKeepCallback) {
		if(!o.onKeepCallback.opt_keepLabel)
			$.fn.setGlobalOnKeepCallback(o.onKeepCallback.object, o.onKeepCallback.method);
		else
			$.fn.setGlobalOnKeepCallback(o.onKeepCallback.object, o.onKeepCallback.method, o.onKeepCallback.opt_keepLabel);
	}
	//if(o.resultSetSize) $.fn.setResultSetSize(o.resultSetSize);
	//if(o.linkTarget) $.fn.setLinkTarget(o.linkTarget);
	//if(o.searchCompleteCallback) $.fn.setSearchCompleteCallback(o.searchCompleteCallback.object, o.searchCompleteCallback.method);
	if(o.searchStartingCallback) $.fn.setGlobalSearchStartingCallback(o.searchStartingCallback.object, o.searchStartingCallback.method);
	
}

//Used for error reporting.
jQuery.warn = function(name, obj) {
	$.log("WARNING- Possibly invalid '" + name + "' : " + obj);
}

//Used for debugging.
jQuery.log = function (message) {
	if (window.console) {
		console.debug(message);
	} else {
		alert(message);
	}
};

//Initialize global vars, only allocates first time called.
jQuery.initializeGlobals = function () {
	if (!haveInitializedGlobals) {
		try {
			//initialize theSearchControl
			theSearchControl = new google.search.SearchControl();
			theSearcherOptions = new google.search.SearcherOptions();
			theDrawOptions = new google.search.DrawOptions();
			
            theWebSearch = new google.search.WebSearch();
            theLocalSearch = new google.search.LocalSearch();
            theVideoSearch = new google.search.VideoSearch();
            theBlogSearch = new google.search.BlogSearch();
            theNewsSearch = new google.search.NewsSearch();
            theBookSearch = new google.search.BookSearch();
            theImageSearch = new google.search.ImageSearch();
            thePatentSearch = new google.search.PatentSearch();
            
			//more to come...
			haveInitializedGlobals = true;
		} catch(exception) {
			$.log(exception + " \n Try loading Google Search Library.");
		}
	}
}

